/*
Copyright 2010  Murali Devi (profdevi@gmail.com)

This file is part of ComineGL Project.

ComineGL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

ComineGL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with ComineGL.  If not, see <http://www.gnu.org/licenses/>.

This code uses the irrlicht and irrklang libraries.  Please read
the libraries copyrights at 

	irrlicht library:  http://irrlicht.sourceforge.net
	irrklang library:  http://www.ambiera.com/irrklang

*/



//v0.14 copyright Comine.com 20101212U01
#include <stdarg.h>
#include "MStdLib.h"
#include "Global.h"
#include "ComineGLNode.h"


//****************************************************
//** ModuleElements
//****************************************************
static bool GNodeAdd(int key,ISceneNode *node,MCGLNodeInfoType nodetype)
	{
	TRefCount<MCGLNodeInfo>  *newnodeinfo=new TRefCount<MCGLNodeInfo>;
	if(newnodeinfo==NULL)
		{
		return false;
		}

	if(newnodeinfo->Create(GlobalRefSceneMgr,node,nodetype)==false)
		{
		newnodeinfo->Drop();
		return false;
		}

	// Check if node exists already
	if(GlobalNodeList.IsKey(key)==true)
		{
		GlobalNodeList.Remove(key);
		}

	//=There are now no nodes with given key in map
	if(GlobalNodeList.Add(key,newnodeinfo)==false)
		{
		newnodeinfo->Drop();
		return false;
		}

	// Drop References to node
	newnodeinfo->Drop();

	MStdPrintf("Added Node <%s> id=%d\n",newnodeinfo->GetTypeName(),key);

	return true;
	}


///////////////////////////////////////////////////
static IMesh *GMakeMeshRectangle(int width,int height)
	{
	SMesh *mesh=new SMesh;
	if(mesh==NULL)
		{
		return NULL;
		}

	// Allocate Buffer
	SMeshBuffer *buffer=new SMeshBuffer;
	if(buffer==NULL)
		{	
		mesh->drop();
		return NULL;		
		}
	
	// Build up the Rectangle
	buffer->Vertices.push_back(S3DVertex((float)-width/2
			,(float)-height/2,0,0,0,(float)1,SColor(255,255,255,255),0,(float)1) );
	buffer->Vertices.push_back(S3DVertex((float)-width/2,(float)+height/2,0,0,0
			,(float)1,SColor(255,255,255,255),0,0) );
	buffer->Vertices.push_back(S3DVertex((float)+width/2,(float)+height/2,0,0,0
			,(float)1,SColor(255,255,255,255),(float)1,0) );
	buffer->Vertices.push_back(S3DVertex((float)+width/2,(float)-height/2,0,0,0
			,(float)1,SColor(255,255,255,255),(float)1,(float)1) );

	buffer->Indices.push_back(0);
	buffer->Indices.push_back(1);
	buffer->Indices.push_back(3);

	buffer->Indices.push_back(3);
	buffer->Indices.push_back(1);
	buffer->Indices.push_back(2);

	mesh->addMeshBuffer(buffer);
	buffer->drop();
	return mesh;
	}


//****************************************************
//** Exported Functions
//****************************************************
MDLLFUN bool CGLNodeLoadCube(int nodeid,float size)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	ISceneNode *node=GlobalRefSceneMgr->addCubeSceneNode(size);
	if(node==NULL)
		{
		return NULL;
		}

	// Turn off lighting
	node->setMaterialFlag(EMF_LIGHTING,false);

	// Set Global Parent
	node->setParent(GlobalRefSceneMgr->getRootSceneNode());

	// Set Node ID as also of irrlicht (for debuging source code)
	node->setID(nodeid);

	if(GNodeAdd(nodeid,node,CGLNIT_CUBE)==false)
		{
		node->remove();
		return false;
		}

	return true;
	}


////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadCamera(int nodeid,float farplanedistance)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Load up node
	ICameraSceneNode *node=GlobalRefSceneMgr->addCameraSceneNode();
	if(node==NULL)
		{
		return NULL;
		}

	// Set the far plane disance
	node->setFarValue(farplanedistance);
	GlobalRefSceneMgr->setActiveCamera(node);
	node->setParent(GlobalRefSceneMgr->getRootSceneNode());
	node->setID(nodeid);

	if(GNodeAdd(nodeid,node,CGLNIT_CAMERA)==false)
		{
		node->remove();
		return false;
		}

	return true;
	}


/////////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadCameraFPS(int nodeid,float farplanedistance,
		float rotatespeed,float movespeed,bool vertmove)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// First Get the current key mappings
	SKeyMap *keymapptr=NULL;
	int keycount=0;

	TVector<SKeyMap> keymap;
	if(GlobalCameraControl.GetKeyArray(keymap)==true)
		{
		keymapptr = keymap.Get();
		keycount = keymap.GetCount();
		}

	// Load up node
	ICameraSceneNode *node=GlobalRefSceneMgr->addCameraSceneNodeFPS(0,rotatespeed
			,movespeed,-1,keymapptr,keycount,!vertmove,0.0);
	if(node==NULL)
		{
		return NULL;
		}

	// Set the far plane disance
	node->setFarValue(farplanedistance);
	GlobalRefSceneMgr->setActiveCamera(node);
	node->setParent(GlobalRefSceneMgr->getRootSceneNode());
	node->setID(nodeid);

	if(GNodeAdd(nodeid,node,CGLNIT_CAMERA_FPS)==false)
		{
		node->remove();
		return false;
		}	

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadMesh(int nodeid,int meshid)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Load up node
	MCGLMeshInfo *meshinfo=GlobalMeshList.Find(meshid);
	if(meshinfo==NULL)
		{
		MStdPrintf("**No Mesh with id=%d\n",meshid);
		return false;
		}

	IAnimatedMesh *imesh=meshinfo->GetMesh();

	E_ANIMATED_MESH_TYPE meshtype=imesh->getMeshType();

	if(meshtype==EAMT_BSP)
		{
		IMeshSceneNode *node=GlobalRefSceneMgr->addOctreeSceneNode(imesh->getMesh(0));
		if(node==NULL)
			{
			MStdPrintf("**Unable to load node(id=%d)with mesh(id=%d)",nodeid,meshid);
			return false;
			}

		// Turn off lighting
		node->setMaterialFlag(EMF_LIGHTING,false);

		// Set Global Parent
		node->setParent(GlobalRefSceneMgr->getRootSceneNode());

		// Set NodeID
		node->setID(nodeid);

		if(GNodeAdd(nodeid,node,CGLNIT_OCT_TREE)==false)
			{
			node->remove();
			return false;
			}
		}
	else
		{
		IAnimatedMeshSceneNode *node=GlobalRefSceneMgr->addAnimatedMeshSceneNode(meshinfo->GetMesh());
		if(node==NULL)
			{
			MStdPrintf("**Unable to load node(id=%d)with mesh(id=%d)",nodeid,meshid);
			return false;
			}

		// Turn off lighting
		node->setMaterialFlag(EMF_LIGHTING,false);

		// Set Global Parent
		node->setParent(GlobalRefSceneMgr->getRootSceneNode());

		// Set NodeID
		node->setID(nodeid);

		if(GNodeAdd(nodeid,node,CGLNIT_ANIMATED_MESH)==false)
			{
			node->remove();
			return false;
			}	
		}

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadSkyBox(int nodeid,int texfront,int texback,int texleft,int texright,int texup,int texdown)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	//**Find all the textures
	MCGLTextureInfo *texfrontinfo=GlobalTextureList.Find(texfront);
	if(texfrontinfo==NULL)
		{
		MStdPrintf("**Unable to find front texture id=%d\n",texfront);
		return false;
		}

	MCGLTextureInfo *texbackinfo=GlobalTextureList.Find(texback);
	if(texbackinfo==NULL)
		{
		MStdPrintf("**Unable to find back texture id=%d\n",texback);
		return false;
		}

	MCGLTextureInfo *texleftinfo=GlobalTextureList.Find(texleft);
	if(texleftinfo==NULL)
		{
		MStdPrintf("**Unable to find left texture id=%d\n",texleft);
		return false;
		}

	MCGLTextureInfo *texrightinfo=GlobalTextureList.Find(texright);
	if(texrightinfo==NULL)
		{
		MStdPrintf("**Unable to find right texture id=%d\n",texright);
		return false;
		}

	MCGLTextureInfo *texupinfo=GlobalTextureList.Find(texup);
	if(texupinfo==NULL)
		{
		MStdPrintf("**Unable to find up texture id=%d\n",texup);
		return false;
		}

	MCGLTextureInfo *texdowninfo=GlobalTextureList.Find(texdown);
	if(texdowninfo==NULL)
		{
		MStdPrintf("**Unable to find down texture id=%d\n",texdown);
		return false;
		}

	ISceneNode *node=GlobalRefSceneMgr->addSkyBoxSceneNode(texupinfo->GetTexture(),
			texdowninfo->GetTexture(),texleftinfo->GetTexture(),texrightinfo->GetTexture(),
			texfrontinfo->GetTexture(),texbackinfo->GetTexture());


	// Set Global Parent
	node->setParent(GlobalRefSceneMgr->getRootSceneNode());

	// Set NodeID
	node->setID(nodeid);

	if(GNodeAdd(nodeid,node,CGLNIT_ANIMATED_MESH)==false)
		{
		node->remove();
		return false;
		}	

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadEmpty(int nodeid)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Load up node
	ISceneNode *node=GlobalRefSceneMgr->addEmptySceneNode();
	if(node==NULL)
		{
		return NULL;
		}

	// Set the far plane disance
	node->setParent(GlobalRefSceneMgr->getRootSceneNode());
	node->setID(nodeid);

	if(GNodeAdd(nodeid,node,CGLNIT_EMPTY)==false)
		{
		node->remove();
		return false;
		}

	return true;	
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadWater(int nodeid,int meshid,float height,float speed,float length)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Load up Mesh
	MCGLMeshInfo *meshinfo=GlobalMeshList.Find(meshid);
	if(meshinfo==NULL)
		{
		MStdPrintf("**No Mesh with id=%d\n",meshid);
		return false;
		}

	// Load up node
	ISceneNode *node=GlobalRefSceneMgr->addWaterSurfaceSceneNode
			(meshinfo->GetMesh()->getMesh(0),height,speed,length);
	if(node==NULL)
		{
		return NULL;
		}

	// Turn off lighting
	node->setMaterialFlag(EMF_LIGHTING,false);

	// Set Global Parent
	node->setParent(GlobalRefSceneMgr->getRootSceneNode());

	if(GNodeAdd(nodeid,node,CGLNIT_WATER_SURFACE)==false)
		{
		node->remove();
		return false;
		}
	
	return true;
	}


/////////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadBillboard(int nodeid,float width,float height)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Load up node
	ISceneNode *node=GlobalRefSceneMgr->addBillboardSceneNode(0,dimension2d<float>(width,height));
	if(node==NULL)
		{
		MStdPrintf("**Unable to load bill board\n");
		return false;
		}

	// Turn off lighting
	node->setMaterialFlag(EMF_LIGHTING,false);

	// Set Global Parent
	node->setParent(GlobalRefSceneMgr->getRootSceneNode());

	if(GNodeAdd(nodeid,node,CGLNIT_BILLBOARD)==false)
		{
		node->remove();
		return false;
		}
	
	return true;
	}


//////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadFontText(int nodeid,int fontid,int size,const char *fmt,...)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	MCGLFontInfo *fontinfo=GlobalFontList.Find(fontid);
	if(fontinfo==NULL)
		{
		MStdPrintf("**Unable to find font %d\n",fontid);
		return false;
		}	
	
	ISceneNode *fontnode=GlobalRefSceneMgr->addEmptySceneNode();
	if(fontnode==NULL)
		{
		MStdPrintf("**Unable to add an empty scene node\n",__LINE__);
		return false;
		}

	// Build up the string
	char buf[200];
	va_list args;
	va_start(args,fmt);

	#ifdef WIN32
	int length=vsnprintf_s(buf,sizeof(buf)-1,_TRUNCATE,fmt,args);
	#else
	int length=vsnprintf(buf,sizeof(buf)-1,fmt,args);
	#endif // WIN32

	va_end(args);

	int i;
	for(i=0;buf[i]!=0 && i<sizeof(buf)-1;++i)
		{
		ITexture *texture=fontinfo->GetChar(buf[i]);
		if(texture==NULL)
			{
			texture=fontinfo->GetChar(' ');
			if(texture==NULL)
				{
				continue;
				}
			}

		IMesh *newmesh=GMakeMeshRectangle(size,size);
		if(newmesh==NULL)
			{
			continue;
			}
		
		IMeshSceneNode *newnode=GlobalRefSceneMgr->addMeshSceneNode(newmesh);
		if(newnode==NULL)
			{
			continue;
			}

		// Now Drop Reference
		newmesh->drop();

		newnode->setPosition(vector3d<float>((float)i*size,0,0) );
		newnode->setMaterialTexture(0,texture);
		newnode->setMaterialFlag(EMF_LIGHTING,false);
		newnode->setMaterialType(EMT_TRANSPARENT_ALPHA_CHANNEL);
		newnode->setParent(fontnode);
		newnode->updateAbsolutePosition();
		}

	if(GNodeAdd(nodeid,fontnode,CGLNIT_FONT_TEXT)==false)
		{
		MStdPrintf("**Unable to load font text node %d\n",nodeid);
		fontnode->drop();
		return false;
		}

	// Turn off lighting
	fontnode->setMaterialFlag(EMF_LIGHTING,false);
	fontnode->setParent(GlobalRefSceneMgr->getRootSceneNode());
	fontnode->setID(nodeid);

	return true;
	}


//////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadSkyDome(int nodeid,int textureid,float fov)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find textureid
	MCGLTextureInfo *textureinfo=GlobalTextureList.Find(textureid);
	if(textureinfo==NULL)
		{
		MStdPrintf("**Unable to find texure %d\n",textureid);
		return false;
		}

	// 
	// Load up terain node
	ISceneNode *node=GlobalRefSceneMgr->addSkyDomeSceneNode(textureinfo->GetTexture(),50,50,1,2*fov/360);
	if(node==NULL)
		{
		MStdPrintf("Unable to load sky dome scene node %d\n",nodeid);
		return NULL;
		}

	if(GNodeAdd(nodeid,node,CGLNIT_SKY_DOME)==false)
		{
		node->remove();
		MStdPrintf("Unable to load sky dome node %d\n",nodeid);
		return NULL;
		}

	// Turn off lighting
	node->setMaterialFlag(EMF_LIGHTING,false);

	node->setParent(GlobalRefSceneMgr->getRootSceneNode());
	node->setID(nodeid);

	return true;	
	}

//////////////////////////////////////////////
MDLLFUN bool CGLNodeLoadTerrain(int nodeid,const char *terrain)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Load up terain node
	ITerrainSceneNode *node=GlobalRefSceneMgr->addTerrainSceneNode(terrain
			,0,-1,vector3d<float>(0,0,0),vector3d<float>(0,0,0)
			,vector3d<float>(1,1,1),SColor(255,255,255,255)
			,5,ETPS_17);
	if(node==NULL)
		{
		MStdPrintf("Unable to load terrain scene node %d\n",nodeid);
		return NULL;
		}

	// Create a node selector
	ITriangleSelector *selector;
	selector=GlobalRefSceneMgr->createTerrainTriangleSelector(node);
	if(selector==NULL)
		{
		MStdPrintf("Unable to create triangle selector for terrain node\n");
		return NULL;
		}

	// Attach selector to node
	node->setTriangleSelector(selector);
	selector->drop();

	if(GNodeAdd(nodeid,node,CGLNIT_TERRAIN)==false)
		{
		node->remove();
		MStdPrintf("Unable to load font text node %d\n",nodeid);
		return NULL;
		}

	// Turn off lighting
	node->setMaterialFlag(EMF_LIGHTING,false);

	node->setParent(GlobalRefSceneMgr->getRootSceneNode());
	node->setID(nodeid);
	
	return true;	
	}


//////////////////////////////////////////////
MDLLFUN bool CGLNodeExists(int nodeid)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	return GlobalNodeList.IsKey(nodeid);
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeUnload(int nodeid)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	if(GlobalNodeList.Remove(nodeid)==false)
		{
		return false;
		}

	return true;
	}


////////////////////////////////////////////
MDLLFUN bool CGLNodeUnloadAll(void)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	if(GlobalNodeList.Clear()==false)
		{
		return false;
		}
	
	return true;
	}


////////////////////////////////////////////////
MDLLFUN int CGLNodeGetCount(void)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return 0;
		}
	
	return GlobalNodeList.GetCount();	
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeSetPosition(int nodeid,float x,float y,float z)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	MCGLNodeInfo *nodeinfo=GlobalNodeList.Find(nodeid);
	if(nodeinfo==NULL)
		{
		MStdPrintf("SetPosition on node failed.  No Node id %d\n",nodeid);
		return false;
		}

	ISceneNode *scenenode=nodeinfo->GetNode();
	scenenode->setPosition(vector3df(x,y,z) );
	
	return true;
	}


/////////////////////////////////////////////////
MDLLFUN bool CGLNodeGetPosition(int nodeid,float &x,float &y,float &z)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	inode->updateAbsolutePosition();
	vector3d<float> position=inode->getPosition();
	x=position.X;
	y=position.Y;
	z=position.Z;

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeGetAbsolutePosition(int nodeid,float &x,float &y,float &z)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	vector3d<float> position=inode->getAbsolutePosition();
	x=position.X;
	y=position.Y;
	z=position.Z;

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeSetRotation(int nodeid,float rx,float ry,float rz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	
	inode->setRotation(vector3d<float>(rx,ry,rz) );
	inode->updateAbsolutePosition();
	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeGetRotation(int nodeid,float &rx,float &ry,float &rz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	inode->updateAbsolutePosition();
	vector3d<float> position=inode->getRotation();
	rx=position.X;
	ry=position.Y;
	rz=position.Z;

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeAddPosition(int nodeid,float dx,float dy,float dz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	
	vector3d<float> vec=inode->getPosition();
	vec.X += dx;
	vec.Y += dy;
	vec.Z += dz;

	inode->setPosition(vec);
	inode->updateAbsolutePosition();
	return true;
	}


/////////////////////////////////////////////////
MDLLFUN bool CGLNodeGetUpVector(int nodeid,float &nx,float &ny,float &nz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	const matrix4 &world=inode->getAbsoluteTransformation();

	nx=world(1,0);
	ny=world(1,1);
	nz=world(1,2);
	return true;
	}


/////////////////////////////////////////////////
MDLLFUN bool CGLNodeGetFrontVector(int nodeid,float &nx,float &ny,float &nz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	const matrix4 &world=inode->getAbsoluteTransformation();

	nx=world(2,0);
	ny=world(2,1);
	nz=world(2,2);
		
	return true;
	}


/////////////////////////////////////////////////
MDLLFUN bool CGLNodeGetRightVector(int nodeid,float &nx,float &ny,float &nz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	const matrix4 &world=inode->getAbsoluteTransformation();

	nx=world(0,0);
	ny=world(0,1);
	nz=world(0,2);

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeSetTexture(int nodeid,int texid,int layer)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	MCGLTextureInfo *texture=GlobalTextureList.Find(texid);
	if(texture==NULL)
		{
		return false;
		}

	ISceneNode *scenenode=node->GetNode();
	MStdAssert(scenenode!=NULL);

	ITexture *textureptr=texture->GetTexture();
	MStdAssert(textureptr!=NULL);

	scenenode->setMaterialTexture(layer,textureptr);
	
	return true;
	}


///////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeSetScale(int nodeid,float sx,float sy,float sz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	inode->setScale(vector3d<float>(sx,sy,sz) );
	inode->updateAbsolutePosition();

	return true;	
	}


///////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeSetParent(int nodeid,int newparent,bool keeprelativeposition)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	if(nodeid==newparent)
		{
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	// Find Node
	MCGLNodeInfo *nodeparent=GlobalNodeList.Find(newparent);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find parent node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	ISceneNode *inodeparent=nodeparent->GetNode();

	if(keeprelativeposition==true)
		{
		inode->updateAbsolutePosition();
		matrix4 nodetrans=inode->getAbsoluteTransformation();

		inode->setParent(inodeparent);

		inodeparent->updateAbsolutePosition();

		matrix4 newparenttrans=inodeparent->getAbsoluteTransformation();

		matrix4 newparenttransinv;
		newparenttrans.getInverse(newparenttransinv);

		matrix4 prod=newparenttransinv*nodetrans;
		inode->setRotation(prod.getRotationDegrees());
		inode->setPosition(prod.getTranslation());
		inode->updateAbsolutePosition();
		}
	else
		{
		// Remember that child will move
		inode->setParent(inodeparent );
		inode->updateAbsolutePosition();
		}
	
	return true;
	}


///////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeSetParentRoot(int nodeid,bool keeprelativeposition)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	if(inode->getParent()==GlobalRefSceneMgr->getRootSceneNode()
			|| inode->getParent()==NULL)
		{
		//=Node has root parent
		return true;
		}

	if(keeprelativeposition==true)
		{
		inode->updateAbsolutePosition();
		matrix4 nodetrans=inode->getAbsoluteTransformation();

		ISceneNode *rootnode=GlobalRefSceneMgr->getRootSceneNode();		
		inode->setParent(rootnode);

		rootnode->updateAbsolutePosition();
		matrix4 rootpos=rootnode->getAbsoluteTransformation();

		matrix4 rootposinv;
		rootpos.getInverse(rootposinv);

		matrix4 prod=rootposinv*nodetrans;

		inode->setRotation(prod.getRotationDegrees());
		inode->setPosition(prod.getTranslation());
		inode->updateAbsolutePosition();
		}
	else
		{
		//=Position will move
		inode->setParent(GlobalRefSceneMgr->getRootSceneNode() );
		inode->updateAbsolutePosition();
		}
	
	return true;
	}


///////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeSetVisible(int nodeid,bool visible)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	inode->setVisible(visible);
	inode->updateAbsolutePosition();

	return true;
	}


///////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeIsVisible(int nodeid)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	return inode->isVisible();
	}


///////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeCameraSetActive(int nodeid)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Search for camera node
	MCGLNodeInfo *nodeinfo=GlobalNodeList.Find(nodeid);
	if(nodeinfo==NULL)
		{
		MStdPrintf("**Unable to find camera node %d\n",nodeid);
		return false;
		}

	if(nodeinfo->GetNodeType()!=CGLNIT_CAMERA
			&& nodeinfo->GetNodeType()!=CGLNIT_CAMERA_MAYA
			&& nodeinfo->GetNodeType()!=CGLNIT_CAMERA_FPS )
		{
		MStdPrintf("**Node %d is not a camera type\n",nodeid);
		return false;
		}

	GlobalRefSceneMgr->setActiveCamera((ICameraSceneNode *)nodeinfo->GetNode());
	return true;
	}


///////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeCameraLookAt(int nodeid,float x,float y,float z)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	

	// Find Node
	MCGLNodeInfo *nodeinfo=GlobalNodeList.Find(nodeid);
	if(nodeinfo==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	if(nodeinfo->GetNodeType()!=CGLNIT_CAMERA
			&& nodeinfo->GetNodeType()!=CGLNIT_CAMERA_MAYA
			&& nodeinfo->GetNodeType()!=CGLNIT_CAMERA_FPS )
		{
		MStdPrintf("No Camera Found with id %d\n",nodeid);
		return true;
		}

	ICameraSceneNode *cameranode=(ICameraSceneNode *)nodeinfo->GetNode();
	cameranode->setTarget(vector3d<float>(x,y,z) );

	return true;
	}


///////////////////////////////////////////////////////////
MDLLFUN bool CGLNodeAnimatorClearAll(int nodeid)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	inode->removeAnimators();
	return true;	
	}


/////////////////////////////////////////////////
MDLLFUN bool CGLNodeAnimatorAddRotation(int nodeid,float rx,float ry,float rz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNodeAnimator *animator=
			GlobalRefSceneMgr->createRotationAnimator(vector3df(rx,ry,rz));
	if(animator==NULL)
		{
		MStdPrintf("**Unable to add rotation animator for node id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	inode->addAnimator(animator);
	animator->drop();

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeAnimatorAddVelocity(int nodeid,float vx,float vy,float vz)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	// Get Node Position
	vector3df position=inode->getPosition();

	// Calculate target position
	const u32 time=1000000000;
	vector3df targetpos=position+vector3df(vx,vy,vz)*time;
	
	ISceneNodeAnimator *animator=
			GlobalRefSceneMgr->createFlyStraightAnimator(position,targetpos,time);
	if(animator==NULL)
		{
		MStdPrintf("**Unable to add velocity animator for node id=%d\n",nodeid);
		return false;
		}

	inode->addAnimator(animator);
	animator->drop();

	return true;
	}


////////////////////////////////////////////////
MDLLFUN bool CGLNodeAnimatorAddMoveTo(int nodeid,float x,float y,float z,unsigned int timems)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	// Get Node Position
	vector3df position=inode->getPosition();
	
	ISceneNodeAnimator *animator=
			GlobalRefSceneMgr->createFlyStraightAnimator(position
				,vector3df(x,y,z),timems);
	if(animator==NULL)
		{
		MStdPrintf("**Unable to add moveto animator for node id=%d\n",nodeid);
		return false;
		}

	inode->addAnimator(animator);
	animator->drop();

	return true;	
	}


/////////////////////////////////////////////////
MDLLFUN bool CGLNodeAnimatorAddCollisionResponse(int nodeid,int nodemapid,int meshid
		,int polycount,float nodesize,float gravity)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	// Find Map Node
	MCGLNodeInfo *mapnode=GlobalNodeList.Find(nodemapid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	MCGLMeshInfo *animmesh=GlobalMeshList.Find(meshid);
	if(animmesh==NULL)
		{
		MStdPrintf("**Unable to find mesh with id=%d\n",meshid);
		return false;
		}

	IMesh *mesh=animmesh->GetMesh()->getMesh(0);
	if(mesh==NULL)
		{
		return false;
		}

	// Create selector
	ITriangleSelector *selector;
	if(inode->getTriangleSelector()==NULL)
		{
		selector=GlobalRefSceneMgr->createOctreeTriangleSelector(mesh,mapnode->GetNode(),polycount);
		if(selector==NULL)
			{
			return false;
			}

		// Attach selector to node
		inode->setTriangleSelector(selector);
		selector->drop();
		}
	else
		{
		selector=inode->getTriangleSelector();
		}

	ISceneNodeAnimatorCollisionResponse *colanim;
	colanim=GlobalRefSceneMgr->createCollisionResponseAnimator(selector,node->GetNode()
			,vector3d<float>(nodesize,nodesize,nodesize)
			,vector3d<float>(0,gravity,0) );
	if(colanim==NULL)
		{
		return false;
		}

	inode->addAnimator(colanim);
	colanim->drop();
	return true;
	}


//////////////////////////////////////////////////
MDLLFUN bool CGLNodeAnimatorAddCollisionResponseTerrain(int nodeid,int terrainnodeid,float gravity)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}

	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	MCGLNodeInfo *mapnode=GlobalNodeList.Find(terrainnodeid);
	if(mapnode==NULL)
		{
		MStdPrintf("**Unable to find terrain node with id=%d\n",terrainnodeid);
		return false;
		}

	if(mapnode->GetNodeType()!=CGLNIT_TERRAIN)
		{
		MStdPrintf("**Node %d is not a terrain type\n",terrainnodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();		
	ITerrainSceneNode *terrainnode=(ITerrainSceneNode *)mapnode->GetNode();

	// Create selector
	ITriangleSelector *selector;
	if(terrainnode->getTriangleSelector()!=NULL)
		{
		selector=GlobalRefSceneMgr->createTerrainTriangleSelector(terrainnode);
		if(selector==NULL)
			{
			MStdPrintf("Unable to create triangle selector for terrain node\n");
			return false;
			}

		// Attach selector to node
		terrainnode->setTriangleSelector(selector);
		selector->drop();
		}
	else
		{
		selector=terrainnode->getTriangleSelector();
		}

	ISceneNodeAnimatorCollisionResponse *colanim;
	colanim=GlobalRefSceneMgr->createCollisionResponseAnimator(selector,inode
			,vector3d<float>(60,60,60)
			,vector3d<float>(0,gravity,0) );
	if(colanim==NULL)
		{
		MStdPrintf("**Unable to create collision response animator for node %d\n",nodeid);
		return false;
		}

	inode->addAnimator(colanim);
	colanim->drop();
	return true;
	}


//////////////////////////////////////////////////
MDLLFUN bool CGLNodeAABBEnable(int nodeid,bool visible)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();
	E_DEBUG_SCENE_TYPE type;
	type=(E_DEBUG_SCENE_TYPE)inode->isDebugDataVisible();

	if(visible==true)
		{
		inode->setDebugDataVisible((E_DEBUG_SCENE_TYPE)(type|EDS_BBOX));
		}
	else
		{
		inode->setDebugDataVisible((E_DEBUG_SCENE_TYPE)(type&(~EDS_BBOX)));
		}

	return true;
	}


/////////////////////////////////////////////////////
MDLLFUN bool CGLNodeAABBHitTestNodes(int nodeid1,int nodeid2)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node1=GlobalNodeList.Find(nodeid1);
	if(node1==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid1);
		return false;
		}

	// Find Node
	MCGLNodeInfo *node2=GlobalNodeList.Find(nodeid2);
	if(node2==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid2);
		return false;
		}

	ISceneNode *inode1=node1->GetNode();
	ISceneNode *inode2=node2->GetNode();

	bool ret;
	ret=inode1->getTransformedBoundingBox().intersectsWithBox(
			inode2->getTransformedBoundingBox() );
	
	return ret;
	}


//////////////////////////////////////////////////
MDLLFUN bool CGLNodeAABBHitTestPoint(int nodeid,float x,float y,float z)
	{
	if(GlobalInitialized==false)
		{
		MStdPrintf("**Engine is not initialized\n");
		return false;
		}
	
	// Find Node
	MCGLNodeInfo *node=GlobalNodeList.Find(nodeid);
	if(node==NULL)
		{
		MStdPrintf("**Unable to find node with id=%d\n",nodeid);
		return false;
		}

	ISceneNode *inode=node->GetNode();

	bool ret;
	ret=inode->getTransformedBoundingBox().isPointInside(vector3d<float>(x,y,z) );	
	return ret;
	}
	
